// Copyright 2017 Baidu Inc. All Rights Reserved.
// Author: tai xiurong (taixiurong@baidu.com)
//
// Description: Recorder

#include "baidu_recorder.h"
#include "baidu_time_calculate.h"
#include "baidu_ca_object.h"
#include "baidu_status_reporter.h"
#include "baidu_measure_stack.h"
#include "heap_monitor.h"
#include "duer_log.h"

namespace duer {
enum _baidu_record_state {
    REC_STOPPING,
    REC_STOPPED,
    REC_STARTING,
    REC_STARTED,
};

Recorder::IPlugin::~IPlugin() {
}

Recorder::IListener::~IListener() {
}

Recorder::MiddleWare::MiddleWare() :
    _listener(NULL) {
}

int Recorder::MiddleWare::set_listener(IListener* listener) {
    _listener = listener;
    return 0;
}

int Recorder::MiddleWare::process_start() {
    int rs = -1;
    if (_listener) {
        rs = _listener->on_start();
    }
    return rs;
}

int Recorder::MiddleWare::process_resume() {
    int rs = -1;
    if (_listener) {
        rs = _listener->on_resume();
    }
    return rs;
}

int Recorder::MiddleWare::process_data(const void* data, size_t size) {
    int rs = -1;
    if (_listener) {
        rs = _listener->on_data(data, size);
    }
    return rs;
}

int Recorder::MiddleWare::process_pause() {
    int rs = -1;
    if (_listener) {
        rs = _listener->on_pause();
    }
    return rs;
}

int Recorder::MiddleWare::process_stop() {
    int rs = -1;
    if (_listener) {
        rs = _listener->on_stop();
    }
    return rs;
}

Recorder::MiddleWare::~MiddleWare() {
}

static bool s_is_registered = false;
static unsigned int s_record_error_count = 0;
static unsigned int s_record_drop_invalid_record_count = 0;

void Recorder::add_drop_invalid_record() {
    //TODO thread safe?
    ++s_record_drop_invalid_record_count;
}

static void recorder_report_status(duer::Object& values) {
    values.putInt("sound_record_error_count", s_record_error_count);
    values.putInt("drop_invalid_record_count", s_record_drop_invalid_record_count);
}

Recorder::Recorder(IPlugin* plugin, size_t size, void* data) :
         _plugin(plugin),
         _thread(
#ifdef TARGET_UNO_91H
        osPriorityAboveNormal,
#else
        osPriorityNormal,
#endif
        DEFAULT_STACK_SIZE * 2),
        _state(REC_STOPPED),
        _capacity(size),
        _buff(data) {
    if (!s_is_registered) {
        duer::StatusReporter::obtain().register_report_function(recorder_report_status);
        s_is_registered = true;
    }

	
}
Recorder::Recorder(IPlugin* plugin) :
        _plugin(plugin),
        _thread(
#ifdef TARGET_UNO_91H
        osPriorityAboveNormal,
#else
        osPriorityNormal,
#endif
        DEFAULT_STACK_SIZE * 2),
        _state(REC_STOPPED),
        _capacity(320 * 2 * 3),
        _buff(NULL) {
    if (!s_is_registered) {
        duer::StatusReporter::obtain().register_report_function(recorder_report_status);
        s_is_registered = true;
    }

	
}
Recorder::Recorder(IPlugin* plugin, size_t  size) :
        _plugin(plugin),
        _thread(osPriorityHigh/*osPriorityAboveNormal*/,DEFAULT_STACK_SIZE * 2),
        _state(REC_STOPPED),
        _capacity(size),
        _buff(NULL) {
    if (!s_is_registered) {
        duer::StatusReporter::obtain().register_report_function(recorder_report_status);
        s_is_registered = true;
    }
#ifdef BAIDU_STACK_MONITOR
        register_thread(&_thread, "Recorder");
#endif
}

Recorder::~Recorder() {
#ifdef BAIDU_STACK_MONITOR
    unregister_thread(&_thread);
#endif
}

int Recorder::start() {
    PERFORM_STATISTIC_BEGIN(PERFORM_STATISTIC_START_RECORD, MAX_TIME_CALCULATE_COUNT);
    if (_state == REC_STOPPED) {
        _state = REC_STARTING;
        _thread.start(this, &Recorder::run);
        return 0;
    }
    ++s_record_error_count;
    return -1;
}

int Recorder::pause() {
	if (_state > REC_STOPPED) {
        _state = REC_STOPPING;
		return 0;
    }
    return 0;
}

int Recorder::resume() {
	if (_state == REC_STOPPED||_state == REC_STOPPING) {
        _state = REC_STARTED;
        return 0;
    }
    return 0;
}

int Recorder::stop() {
    PERFORM_STATISTIC_BEGIN(PERFORM_STATISTIC_SOTP_RECORD, MAX_TIME_CALCULATE_COUNT);
    if (_state > REC_STOPPED) {
        _state = REC_STOPPING;
    }
    return 0;
}

int Recorder::set_listener(IListener* listener) {
    if (_listener != listener) {
        _listener = listener;
    }
    return 0;
}


void Recorder::run() {
    int rs = 0;
    _state = REC_STARTED;
    _plugin->start_record();

	char *	_rx_buffer = new char [_capacity];
	
	DUER_LOGI("recorder started");
	_listener ? _listener->on_start() : 0;

    DUER_LOGI("thread: id = %x, used = %d, max = %d", _thread.gettid(), _thread.used_stack(),_thread.max_stack());
	
    PERFORM_STATISTIC_END(PERFORM_STATISTIC_START_RECORD, 0, UNCONTINUOUS_TIME_MEASURE);

	while (_state == REC_STARTED) 
	{	

		PERFORM_STATISTIC_BEGIN(PERFORM_STATISTIC_READ_VOICE_DATA, MAX_TIME_CALCULATE_COUNT);
		rs = _plugin->read(_rx_buffer, _capacity);
		_plugin->read_done();
		PERFORM_STATISTIC_END(PERFORM_STATISTIC_READ_VOICE_DATA, rs, UNCONTINUOUS_TIME_MEASURE);

		PERFORM_STATISTIC_BEGIN(PERFORM_STATISTIC_RECORDER_ON_DATA, MAX_TIME_CALCULATE_COUNT);
		rs = _listener ? _listener->on_data(_rx_buffer, _capacity) : 0;
		PERFORM_STATISTIC_END(PERFORM_STATISTIC_RECORDER_ON_DATA,_capacity,UNCONTINUOUS_TIME_MEASURE);
	}		
exit:
    _plugin->stop_record();
	DUER_LOGI("recorder stoped");
    rs = _listener ? _listener->on_stop() : 0;
	
	if(_rx_buffer)delete []_rx_buffer;
	_rx_buffer = NULL;
	
#ifdef HEAP_MONITOR
    show_heap_info();
#endif

#ifdef BAIDU_STACK_MONITOR
    get_current_thread_stack_usage();
#endif

#ifdef BAIDU_PERFORM_STATISTIC
    PERFORM_STATISTIC_RESULT();
#endif
    _state = REC_STOPPED;
    PERFORM_STATISTIC_END(PERFORM_STATISTIC_SOTP_RECORD, 0, UNCONTINUOUS_TIME_MEASURE);
    PERFORM_STATISTIC_BEGIN(PERFORM_STATISTIC_GET_URL, MAX_TIME_CALCULATE_COUNT);
	
}
}//duer
